package org.example.compare.schedule;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.example.compare.dto.*;
import org.example.compare.global.Global;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 测试数据生成器类，用于为recheckCanSend_WeiChi函数生成测试数据
 * 该函数使用到的非函数参数列表外部变量包括:
 * 1. SchData.hParamSet - 系统参数集，需要获取"MinInLibSTDPer"参数
 * 2. SchData.pPositionDtos - 工位数据数组
 * 3. SchData.orderId2Order - 订单映射
 * 4. OrderProcess.mScheduling - 工序调度信息
 * 5. Score.pOp - 工序信息
 * 6. PreScheduling.getProcessWorkingByPosition - 获取工位当前工序的方法
 */
public class RecheckCanSendWeiChiTestDataGenerator {

    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final Random random = new Random();

    static {
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * 生成随机测试数据并保存到文件
     */
    public static void generateRandomTestData(int iteration) throws IOException {
        String basePath = "../../test_data/recheckCanSend_WeiChi/random_case_" + iteration;
        File baseDir = new File(basePath);

        // 清空文件夹
        clearDirectory(baseDir);

        if (!baseDir.exists()) {
            baseDir.mkdirs();
        }

        // 生成测试数据
        generateSysParamData(basePath);
        Map<String, OrderDto> orderId2Order = generateOrderData(basePath);
        Map<Long, PositionDto> pPositionDtos = generatePositionDtosData(basePath);
        generateScoreData(basePath, orderId2Order, pPositionDtos);
    }

    /**
     * 生成手动测试数据并保存到文件
     */
    public static void generateManualTestData(int caseNumber) throws IOException {
        String basePath = "../../test_data/recheckCanSend_WeiChi/manual_case_" + caseNumber;
        File baseDir = new File(basePath);

        // 清空文件夹
        clearDirectory(baseDir);

        if (!baseDir.exists()) {
            baseDir.mkdirs();
        }

        if (caseNumber == 1) {
            generateManualTestCase1(basePath);
        } else if (caseNumber == 2) {
            generateManualTestCase2(basePath);
        }
    }

    /**
     * 生成手动测试案例1 - 基本正常情况，返回true
     */
    private static void generateManualTestCase1(String basePath) throws IOException {
        // 生成系统参数
        Map<String, SysParam> hParamSet = new HashMap<>();
        
        // MinInLibSTDPer 参数 - 固定值 300 (5分钟)
        SysParam minInLibSTDPer = new SysParam();
        minInLibSTDPer.setParamCode("MinInLibSTDPer");
        minInLibSTDPer.setParamDefaultValue("300");
        hParamSet.put("MinInLibSTDPer", minInLibSTDPer);
        
        // AllInLibUseTotal0Box1 参数 - 固定值 0
        SysParam allInLibUseTotal0Box1 = new SysParam();
        allInLibUseTotal0Box1.setParamCode("AllInLibUseTotal0Box1");
        allInLibUseTotal0Box1.setParamDefaultValue("0");
        hParamSet.put("AllInLibUseTotal0Box1", allInLibUseTotal0Box1);
        
        objectMapper.writeValue(new File(basePath + "/hParamSet.json"), hParamSet);

        // 生成订单数据
        Map<String, OrderDto> orderId2Order = new HashMap<>();
        OrderDto order1 = OrderDto.InitOrder();
        order1.setMLocalOrderNum("TEST1001123456");
        order1.setMiTotalPlanCnt(1000);
        orderId2Order.put("TEST1001123456", order1);
        objectMapper.writeValue(new File(basePath + "/orderId2Order.json"), orderId2Order);

        // 生成工位数据
        Map<Long, PositionDto> pPositionDtos = new HashMap<>();
        
        // 空闲工位
        PositionDto position1 = new PositionDto();
        position1.setPositionId(10001L);
        position1.setMiPosStatus(Global.FREE_P_S); // 空闲状态
        pPositionDtos.put(10001L, position1);
        
        // 仅在产工位
        PositionDto position2 = new PositionDto();
        position2.setPositionId(10002L);
        position2.setMiPosStatus(Global.IN_PRO_ONLY_P_S); // 仅在产状态
        pPositionDtos.put(10002L, position2);
        
        objectMapper.writeValue(new File(basePath + "/pPositionDtos.json"), pPositionDtos);

        // 生成工序集数据
        Map<Long, OrderProcess> hProcessSet = new HashMap<>();

        // 工序1 (正常状态)
        OrderProcess process1 = OrderProcess.InitOrderProcess(order1);
        process1.setProcessId(1001L);
        process1.setOrderProcessId(1001L);
        process1.setMfProcessTotalTime(120.0f); // 2分钟标准工时

        ProcessSch scheduling1 = new ProcessSch();
        scheduling1.setMbHoldFlag(false);
        scheduling1.setMbNGFlag(false);
        
        // 设置在产工位
        Set<Long> workingPos1 = new HashSet<>();
        workingPos1.add(10002L); // 10002号工位正在工作
        scheduling1.setMisWorkingPos(workingPos1);
        
        // 设置做过的工位
        Set<Long> haveDonePos1 = new HashSet<>();
        haveDonePos1.add(10001L); // 10001号工位做过
        scheduling1.setMisHaveDonePos(haveDonePos1);
        
        // 设置在库件数
        CBoxSet boxesInLib1 = new CBoxSet();
        boxesInLib1.setMiCutCnt(100); // 100裁片件数
        boxesInLib1.setMiBoxCnt(5);   // 5个筐
        scheduling1.setMBoxesInLib(boxesInLib1);
        
        process1.setMScheduling(scheduling1);
        hProcessSet.put(1001L, process1);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/hProcessSet.json"), hProcessSet);

        // 生成分数数据
        List<Score> scores = new ArrayList<>();
        
        // 分数1 - 空闲工位
        Score score1 = new Score();
        score1.setPositionId(10001L);
        score1.setProcessID(1001L);
        score1.setTotal(80.0);
        score1.setPOp(process1);
        score1.setRemark(""); // 初始化remark为空字符串
        double[] scoreItems1 = new double[20];
        Arrays.fill(scoreItems1, 5.0);
        score1.setScoreItem(scoreItems1);
        scores.add(score1);
        
        // 分数2 - 在产工位
        Score score2 = new Score();
        score2.setPositionId(10002L);
        score2.setProcessID(1001L);
        score2.setTotal(75.0);
        score2.setPOp(process1);
        score2.setRemark(""); // 初始化remark为空字符串
        double[] scoreItems2 = new double[20];
        Arrays.fill(scoreItems2, 4.5);
        score2.setScoreItem(scoreItems2);
        scores.add(score2);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/scores.json"), scores);
    }

    /**
     * 生成手动测试案例2 - 能产生false结果的情况
     * 满足以下条件使第5个if成立而前面的if都不成立：
     * 1. 工位不是空闲状态
     * 2. 工位当前有正在执行的工序
     * 3. 当前工序与测试工序不同
     * 4. 当前工序是全部在库
     * 5. minStdPer > stdInLib 成立
     */
    private static void generateManualTestCase2(String basePath) throws IOException {
        // 生成系统参数
        Map<String, SysParam> hParamSet = new HashMap<>();

        // MinInLibSTDPer 参数 - 固定值 600 (10分钟，设置得足够大以便触发条件)
        SysParam minInLibSTDPer = new SysParam();
        minInLibSTDPer.setParamCode("MinInLibSTDPer");
        minInLibSTDPer.setParamDefaultValue("600");
        hParamSet.put("MinInLibSTDPer", minInLibSTDPer);

        // AllInLibUseTotal0Box1 参数 - 固定值 0
        SysParam allInLibUseTotal0Box1 = new SysParam();
        allInLibUseTotal0Box1.setParamCode("AllInLibUseTotal0Box1");
        allInLibUseTotal0Box1.setParamDefaultValue("0");
        hParamSet.put("AllInLibUseTotal0Box1", allInLibUseTotal0Box1);

        objectMapper.writeValue(new File(basePath + "/hParamSet.json"), hParamSet);

        // 生成订单数据
        Map<String, OrderDto> orderId2Order = new HashMap<>();
        OrderDto order1 = OrderDto.InitOrder();
        order1.setMLocalOrderNum("TEST1003456789");
        order1.setMiTotalPlanCnt(500);

        // 为订单添加工序数据
        Map<Integer, OrderProcess> processMap = new HashMap<>();
        
        // 工序1 (当前在产工序 - 工序ID为2001L)
        OrderProcess process1 = OrderProcess.InitOrderProcess(order1);
        process1.setProcessId(2001L);
        process1.setOrderProcessId(2001L);
        process1.setMPartId(100L);
        process1.setMiPartSeqNum(1);
        process1.setMfProcessTotalTime(5.0f); // 5秒标准工时 (较小的标准工时)
        process1.setMiFinishedCnt(498); // 完成数量为498，只差2个就完成了
        
        // 为工序1设置调度信息
        ProcessSch scheduling1_order = new ProcessSch();
        scheduling1_order.setMbHoldFlag(false);
        scheduling1_order.setMbNGFlag(false);
        
        // 设置在产工位
        Set<Long> workingPos1_order = new HashSet<>();
        workingPos1_order.add(20001L); // 20001号工位正在工作
        scheduling1_order.setMisWorkingPos(workingPos1_order);
        
        // 设置做过的工位
        Set<Long> haveDonePos1_order = new HashSet<>();
        haveDonePos1_order.add(20003L); // 20003号工位做过 (不存在的工位)
        scheduling1_order.setMisHaveDonePos(haveDonePos1_order);
        
        // 设置在库件数
        CBoxSet boxesInLib1_order = new CBoxSet();
        boxesInLib1_order.setMiCutCnt(2); // 2裁片件数 (很小)
        boxesInLib1_order.setMiBoxCnt(1);   // 1个筐 (很小)
        scheduling1_order.setMBoxesInLib(boxesInLib1_order);
        
        process1.setMScheduling(scheduling1_order);
        processMap.put(1, process1);
        
        // 工序2 (测试工序 - 工序ID为3001L)
        OrderProcess process2 = OrderProcess.InitOrderProcess(order1);
        process2.setProcessId(3001L);
        process2.setOrderProcessId(3001L);
        process2.setMPartId(100L);
        process2.setMiPartSeqNum(2);
        process2.setMfProcessTotalTime(120.0f); // 2分钟标准工时
        process2.setMiFinishedCnt(0); // 完成数量为0
        
        // 为工序2设置调度信息
        ProcessSch scheduling2_order = new ProcessSch();
        scheduling2_order.setMbHoldFlag(false);
        scheduling2_order.setMbNGFlag(false);
        
        // 设置在产工位
        Set<Long> workingPos2_order = new HashSet<>();
        scheduling2_order.setMisWorkingPos(workingPos2_order);
        
        // 设置做过的工位
        Set<Long> haveDonePos2_order = new HashSet<>();
        haveDonePos2_order.add(20003L); // 20003号工位做过 (不存在的工位)
        scheduling2_order.setMisHaveDonePos(haveDonePos2_order);
        
        // 设置在库件数
        CBoxSet boxesInLib2_order = new CBoxSet();
        boxesInLib2_order.setMiCutCnt(2); // 2裁片件数 (很小)
        boxesInLib2_order.setMiBoxCnt(1);   // 1个筐 (很小)
        scheduling2_order.setMBoxesInLib(boxesInLib2_order);
        
        process2.setMScheduling(scheduling2_order);
        processMap.put(2, process2);
        
        Map<Long, Map<Integer, OrderProcess>> orderProcessSetGroupByPart = new HashMap<>();
        orderProcessSetGroupByPart.put(100L, processMap);
        order1.setMOrderProcessSetGroupByPart(orderProcessSetGroupByPart);
        
        // 添加工序到全局映射中（通过hProcessSet字段）
        Map<Long, OrderProcess> processId2OrderProcess = new HashMap<>();
        processId2OrderProcess.put(2001L, process1);
        processId2OrderProcess.put(3001L, process2);

        // 添加筐数据
        Map<Long, List<SBoxData>> boxSetGroupByPart = new HashMap<>();
        List<SBoxData> boxes = new ArrayList<>();

        // 添加一个在产筐
        SBoxData box1 = new SBoxData();
        box1.setMiBoxRecordId(50001L);
        box1.setMBoxNum("BOX50001");
        box1.setPartId(100L);
        box1.setMiBoxStatus(Global.IN_PRO_B_S); // 在产状态
        box1.setMStatusInfo("20001"); // 在20001号工位
        box1.setMLocalOrderNum("TEST1003456789"); // 设置订单号
        box1.setMiCurReworkRecordId(0); // 无返工记录
        box1.setMbRedistributeFlag(false); // 未重新分配

        // 设置未完成工序ID，包含2001L（当前工序）
        Set<Long> unDoneProcessID = new HashSet<>();
        unDoneProcessID.add(2001L);
        box1.setMUnDoneProcessID(unDoneProcessID);

        // 设置可以做的工序序号
        Set<Integer> canDoProcessSeq = new HashSet<>();
        canDoProcessSeq.add(1); // 序号1
        box1.setMCanDoProcessSeq(canDoProcessSeq);

        box1.setMiPartSeqNum(1); // 部件序号1
        box1.setMiPlanCnt(2); // 计划数量2

        boxes.add(box1);
        
        boxSetGroupByPart.put(100L, boxes);
        order1.setMCurBoxSetGroupByPart(boxSetGroupByPart);

        orderId2Order.put("TEST1003456789", order1);
        objectMapper.writeValue(new File(basePath + "/orderId2Order.json"), orderId2Order);

        // 生成工位数据
        Map<Long, PositionDto> pPositionDtos = new HashMap<>();

        // 非空闲工位 (测试工位)
        PositionDto position1 = new PositionDto();
        position1.setPositionId(20001L);
        position1.setMiPosStatus(Global.BUSY_P_S); // 非空闲状态
        position1.setMBoxInPro("BOX50001"); // 设置为在产筐
        position1.setMBoxWaitingForPro(""); // 设置为空字符串而不是null
        pPositionDtos.put(20001L, position1);

        objectMapper.writeValue(new File(basePath + "/pPositionDtos.json"), pPositionDtos);

        // 生成工序集数据
        Map<Long, OrderProcess> hProcessSet = new HashMap<>();

        // 工序1 (当前在产工序 - 工序ID为2001L)
        OrderProcess process1_op = OrderProcess.InitOrderProcess(order1);
        process1_op.setProcessId(2001L);
        process1_op.setOrderProcessId(2001L);
        process1_op.setMPartId(100L);
        process1_op.setMiPartSeqNum(1);
        process1_op.setMfProcessTotalTime(5.0f); // 5秒标准工时 (较小的标准工时)
        process1_op.setMiFinishedCnt(498); // 完成数量为498，只差2个就完成了

        ProcessSch scheduling1 = new ProcessSch();
        scheduling1.setMbHoldFlag(false);
        scheduling1.setMbNGFlag(false);

        // 设置在产工位
        Set<Long> workingPos1 = new HashSet<>();
        workingPos1.add(20001L); // 20001号工位正在工作
        scheduling1.setMisWorkingPos(workingPos1);

        // 设置做过的工位
        Set<Long> haveDonePos1 = new HashSet<>();
        haveDonePos1.add(20003L); // 20003号工位做过 (不存在的工位)
        scheduling1.setMisHaveDonePos(haveDonePos1);

        // 设置在库件数 (设置得足够小以便触发条件)
        CBoxSet boxesInLib1 = new CBoxSet();
        boxesInLib1.setMiCutCnt(2); // 2裁片件数 (很小)
        boxesInLib1.setMiBoxCnt(1);   // 1个筐 (很小)
        scheduling1.setMBoxesInLib(boxesInLib1);

        process1_op.setMScheduling(scheduling1);
        hProcessSet.put(2001L, process1_op);

        // 工序2 (测试工序 - 工序ID为3001L)
        OrderProcess process2_op = OrderProcess.InitOrderProcess(order1);
        process2_op.setProcessId(3001L);
        process2_op.setOrderProcessId(3001L);
        process2_op.setMPartId(100L);
        process2_op.setMiPartSeqNum(2);
        process2_op.setMfProcessTotalTime(120.0f); // 2分钟标准工时
        process2_op.setMiFinishedCnt(0); // 完成数量为0

        ProcessSch scheduling2 = new ProcessSch();
        scheduling2.setMbHoldFlag(false);
        scheduling2.setMbNGFlag(false);

        // 设置在产工位 (无工位正在做)
        Set<Long> workingPos2 = new HashSet<>();
        scheduling2.setMisWorkingPos(workingPos2);

        // 设置做过的工位 (测试工位没有做过)
        Set<Long> haveDonePos2 = new HashSet<>();
        haveDonePos2.add(20003L); // 20003号工位做过 (不存在的工位)
        scheduling2.setMisHaveDonePos(haveDonePos2);

        // 设置在库件数 (设置得足够小以便触发条件)
        CBoxSet boxesInLib2 = new CBoxSet();
        boxesInLib2.setMiCutCnt(2); // 2裁片件数 (很小)
        boxesInLib2.setMiBoxCnt(1);   // 1个筐 (很小)
        scheduling2.setMBoxesInLib(boxesInLib2);

        process2_op.setMScheduling(scheduling2);
        hProcessSet.put(3001L, process2_op);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/hProcessSet.json"), hProcessSet);

        // 生成分数数据
        List<Score> scores = new ArrayList<>();

        // 分数1 - 非空闲工位 (应该返回false)
        Score score1 = new Score();
        score1.setPositionId(20001L);
        score1.setProcessID(3001L);
        score1.setTotal(85.0);
        score1.setPOp(process2_op);
        score1.setRemark(""); // 初始化remark为空字符串
        double[] scoreItems1 = new double[20];
        Arrays.fill(scoreItems1, 6.0);
        score1.setScoreItem(scoreItems1);
        scores.add(score1);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/scores.json"), scores);
    }

    /**
     * 清空指定目录下的所有文件
     *
     * @param directory 要清空的目录
     * @throws IOException IO异常
     */
    private static void clearDirectory(File directory) throws IOException {
        if (directory.exists() && directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isFile()) {
                        Files.delete(file.toPath());
                    }
                }
            }
        }
    }

    /**
     * 生成系统参数数据
     */
    private static void generateSysParamData(String basePath) throws IOException {
        Map<String, SysParam> hParamSet = new HashMap<>();

        // MinInLibSTDPer 参数 - 有更高的概率设置为较大值(400-1000)以生成false结果
        SysParam minInLibSTDPer = new SysParam();
        minInLibSTDPer.setParamCode("MinInLibSTDPer");
        if (random.nextInt(10) < 8) {
            // 80%概率设置较大值，更容易产生false结果
            minInLibSTDPer.setParamDefaultValue(String.valueOf(400 + random.nextInt(601))); // 400-1000
        } else {
            // 20%概率设置较小值
            minInLibSTDPer.setParamDefaultValue(String.valueOf(100 + random.nextInt(301))); // 100-400
        }
        hParamSet.put("MinInLibSTDPer", minInLibSTDPer);

        // AllInLibUseTotal0Box1 参数 - 固定值 0
        SysParam allInLibUseTotal0Box1 = new SysParam();
        allInLibUseTotal0Box1.setParamCode("AllInLibUseTotal0Box1");
        allInLibUseTotal0Box1.setParamDefaultValue("0");
        hParamSet.put("AllInLibUseTotal0Box1", allInLibUseTotal0Box1);

        objectMapper.writeValue(new File(basePath + "/hParamSet.json"), hParamSet);
    }

    /**
     * 生成订单数据
     */
    private static Map<String, OrderDto> generateOrderData(String basePath) throws IOException {
        Map<String, OrderDto> orderId2Order = new HashMap<>();

        // 随机生成订单数量 2-5个
        int orderCount = 2 + random.nextInt(4);

        for (int i = 0; i < orderCount; i++) {
            OrderDto order = OrderDto.InitOrder();
            String orderNum = "TEST" + (1000 + i) + "" + (100000 + random.nextInt(900000));
            order.setMLocalOrderNum(orderNum);
            order.setMiTotalPlanCnt(500 + random.nextInt(1001)); // 500-1500

            orderId2Order.put(orderNum, order);
        }

        objectMapper.writeValue(new File(basePath + "/orderId2Order.json"), orderId2Order);
        return orderId2Order;
    }

    /**
     * 生成工位数据
     */
    private static Map<Long, PositionDto> generatePositionDtosData(String basePath) throws IOException {
        Map<Long, PositionDto> pPositionDtos = new HashMap<>();

        // 随机生成工位数量 5-10个
        int positionCount = 5 + random.nextInt(6);

        for (int i = 0; i < positionCount; i++) {
            PositionDto position = new PositionDto();
            long positionId = 10000L + random.nextInt(90000); // 10000-99999的工位ID
            position.setPositionId(positionId);

            // 随机设置工位状态，增加非空闲状态的概率
            // 增加非空闲状态的概率，使更容易产生false结果
            int[] statusOptions = {Global.FREE_P_S, Global.IN_PRO_ONLY_P_S, Global.WAITING_FOR_ONLY_PRO_P_S,
                    Global.IN_THE_WAY_P_S, Global.BUSY_P_S, Global.BUSY_P_S, Global.BUSY_P_S, Global.BUSY_P_S, 
                    Global.BUSY_P_S, Global.STOP_RECV_P_S};
            position.setMiPosStatus(statusOptions[random.nextInt(statusOptions.length)]);

            // 根据工位状态设置合适的筐号信息
            switch (position.getMiPosStatus()) {
                case Global.FREE_P_S:
                    position.setMBoxInPro("");
                    position.setMBoxWaitingForPro("");
                    break;
                case Global.IN_PRO_ONLY_P_S:
                    position.setMBoxInPro("BOX" + String.format("%05d", positionId));
                    position.setMBoxWaitingForPro("");
                    break;
                case Global.WAITING_FOR_ONLY_PRO_P_S:
                    position.setMBoxInPro("");
                    position.setMBoxWaitingForPro("BOX" + String.format("%05d", positionId));
                    break;
                case Global.IN_THE_WAY_P_S:
                    position.setMBoxInPro("");
                    position.setMBoxWaitingForPro("BOX" + String.format("%05d", positionId));
                    break;
                case Global.BUSY_P_S:
                    position.setMBoxInPro("BOX" + String.format("%05d", positionId));
                    position.setMBoxWaitingForPro("BOX" + String.format("%05d", positionId + 50000));
                    break;
                case Global.STOP_RECV_P_S:
                    position.setMBoxInPro("");
                    position.setMBoxWaitingForPro("");
                    break;
                default:
                    position.setMBoxInPro("");
                    position.setMBoxWaitingForPro("");
                    break;
            }

            pPositionDtos.put(positionId, position);
        }

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/pPositionDtos.json"), pPositionDtos);

        return pPositionDtos;
    }

    /**
     * 生成分数数据
     */
    private static void generateScoreData(String basePath, Map<String, OrderDto> orderId2Order,
                                          Map<Long, PositionDto> pPositionDtos) throws IOException {
        // 生成工序集数据
        Map<Long, OrderProcess> hProcessSet = new HashMap<>();

        // 获取订单列表
        List<String> orderNums = new ArrayList<>(orderId2Order.keySet());
        if (orderNums.isEmpty()) {
            // 如果没有订单，创建一个默认订单
            OrderDto defaultOrder = OrderDto.InitOrder();
            defaultOrder.setMLocalOrderNum("DEFAULT_ORDER");
            defaultOrder.setMiTotalPlanCnt(1000);
            orderId2Order.put("DEFAULT_ORDER", defaultOrder);
            orderNums.add("DEFAULT_ORDER");
        }

        // 获取工位列表
        List<Long> positionIds = new ArrayList<>(pPositionDtos.keySet());
        if (positionIds.isEmpty()) {
            // 如果没有工位，创建一些默认工位
            for (int i = 0; i < 5; i++) {
                positionIds.add(10000L + i);
            }
        }

        // 生成订单的筐数据和工序数据，确保能通过getProcessWorkingByPosition和findProcessByOrderPartSeq
        Map<String, OrderDto> fullOrderId2Order = new HashMap<>();
        Map<Long, List<SBoxData>> allBoxes = new HashMap<>();
        
        // 为每个订单生成完整的数据
        for (String orderNum : orderNums) {
            OrderDto order = orderId2Order.get(orderNum);
            if (order == null) {
                order = OrderDto.InitOrder();
                order.setMLocalOrderNum(orderNum);
                order.setMiTotalPlanCnt(500 + random.nextInt(1001));
            }
            
            // 为订单添加工序数据
            Map<Integer, OrderProcess> processMap = new HashMap<>();
            
            // 为每个订单生成3-6个工序
            int processCount = 3 + random.nextInt(4);
            for (int j = 1; j <= processCount; j++) {
                OrderProcess process = OrderProcess.InitOrderProcess(order);
                long processId = Math.abs((long)orderNum.hashCode() * 1000 + j * 100 + random.nextInt(100));
                if (processId <= 0) processId = Math.abs(processId) + 1000;
                process.setProcessId(processId);
                process.setOrderProcessId(processId);
                process.setMPartId(100L); // 部件ID
                process.setMiPartSeqNum(j); // 部件序号
                // 70%概率设置较小的标准工时(5-150秒)，30%概率设置较大的标准工时(150-600秒)
                if (random.nextInt(10) < 7) {
                    process.setMfProcessTotalTime(5.0f + random.nextInt(146)); // 5-150秒标准工时
                } else {
                    process.setMfProcessTotalTime(150.0f + random.nextInt(451)); // 150-600秒标准工时
                }
                process.setMiFinishedCnt(random.nextInt(500)); // 随机完成数量
                
                // 为工序设置调度信息
                ProcessSch scheduling = new ProcessSch();
                scheduling.setMbHoldFlag(random.nextDouble() < 0.1); // 10%概率为挂起状态
                scheduling.setMbNGFlag(random.nextDouble() < 0.1); // 10%概率为NG状态
                
                // 设置在产工位
                Set<Long> workingPos = new HashSet<>();
                int workingPosCount = random.nextInt(3); // 0-2个在产工位
                for (int k = 0; k < workingPosCount; k++) {
                    if (!positionIds.isEmpty()) {
                        workingPos.add(positionIds.get(random.nextInt(positionIds.size()))); // 随机工位ID
                    }
                }
                scheduling.setMisWorkingPos(workingPos);
                
                // 设置做过的工位
                Set<Long> haveDonePos = new HashSet<>();
                int haveDonePosCount = random.nextInt(4); // 0-3个做过的工位
                for (int k = 0; k < haveDonePosCount; k++) {
                    if (!positionIds.isEmpty()) {
                        haveDonePos.add(positionIds.get(random.nextInt(positionIds.size()))); // 随机工位ID
                    }
                }
                scheduling.setMisHaveDonePos(haveDonePos);
                
                // 设置在库件数 - 有很大概率设置得较小以生成false结果
                CBoxSet boxesInLib = new CBoxSet();
                // 70%概率设置较小的值以生成false结果
                if (random.nextInt(10) < 7) {
                    // 设置较小的在库件数和筐数，更容易触发false条件
                    boxesInLib.setMiCutCnt(random.nextInt(10)); // 0-9裁片件数
                    boxesInLib.setMiBoxCnt(random.nextInt(3) + 1);  // 1-3筐数
                } else {
                    boxesInLib.setMiCutCnt(random.nextInt(100) + 10); // 10-109裁片件数
                    boxesInLib.setMiBoxCnt(random.nextInt(20) + 5);  // 5-24筐数
                }
                scheduling.setMBoxesInLib(boxesInLib);
                
                process.setMScheduling(scheduling);
                processMap.put(j, process);
                hProcessSet.put(processId, process);
            }
            
            Map<Long, Map<Integer, OrderProcess>> orderProcessSetGroupByPart = new HashMap<>();
            orderProcessSetGroupByPart.put(100L, processMap);
            order.setMOrderProcessSetGroupByPart(orderProcessSetGroupByPart);

            // 为订单添加筐数据
            Map<Long, List<SBoxData>> boxSetGroupByPart = new HashMap<>();
            List<SBoxData> boxes = new ArrayList<>();
            
            // 为每个工位创建对应的筐数据
            for (Long positionId : positionIds) {
                if (random.nextDouble() < 0.3) { // 30%概率为每个工位创建筐
                    SBoxData box = new SBoxData();
                    long boxRecordId = Math.abs(50000L + (long)orderNum.hashCode() * 1000 + positionId + random.nextInt(1000));
                    if (boxRecordId <= 0) boxRecordId = Math.abs(boxRecordId) + 10000;
                    box.setMiBoxRecordId(boxRecordId);
                    box.setMBoxNum("BOX" + String.format("%05d", boxRecordId));
                    box.setPartId(100L);
                    box.setMiBoxStatus(Global.IN_PRO_B_S); // 在产状态
                    box.setMStatusInfo(String.valueOf(positionId)); // 工位ID
                    box.setMLocalOrderNum(orderNum); // 订单号
                    box.setMiCurReworkRecordId(0); // 无返工记录
                    box.setMbRedistributeFlag(false); // 未重新分配

                    // 设置未完成工序ID
                    Set<Long> unDoneProcessID = new HashSet<>();
                    // 添加一个随机工序ID
                    if (!processMap.isEmpty()) {
                        List<Integer> seqs = new ArrayList<>(processMap.keySet());
                        Integer seq = seqs.get(random.nextInt(seqs.size()));
                        OrderProcess process = processMap.get(seq);
                        if (process != null) {
                            unDoneProcessID.add(process.getOrderProcessId());
                        }
                    }
                    box.setMUnDoneProcessID(unDoneProcessID);

                    // 设置可以做的工序序号
                    Set<Integer> canDoProcessSeq = new HashSet<>();
                    if (!processMap.isEmpty()) {
                        List<Integer> seqs = new ArrayList<>(processMap.keySet());
                        canDoProcessSeq.add(seqs.get(random.nextInt(seqs.size()))); // 随机序号
                    }
                    box.setMCanDoProcessSeq(canDoProcessSeq);

                    box.setMiPartSeqNum(1); // 部件序号1
                    box.setMiPlanCnt(1 + random.nextInt(20)); // 计划数量1-20

                    boxes.add(box);
                    allBoxes.put(boxRecordId, Collections.singletonList(box));
                }
            }
            
            boxSetGroupByPart.put(100L, boxes);
            order.setMCurBoxSetGroupByPart(boxSetGroupByPart);
            
            fullOrderId2Order.put(orderNum, order);
        }

        // 更新订单文件
        objectMapper.writeValue(new File(basePath + "/orderId2Order.json"), fullOrderId2Order);

        // 生成分数数据
        List<Score> scores = new ArrayList<>();

        // 使用已生成的工序ID来创建分数数据
        List<Long> processIds = new ArrayList<>(hProcessSet.keySet());

        for (Long processId : processIds) {
            OrderProcess process = hProcessSet.get(processId);

            // 每个工序对应1-5个工位分数（不超过工位总数）
            int scoreCount = Math.min(1 + random.nextInt(5), positionIds.size());
            Collections.shuffle(positionIds); // 随机打乱

            for (int j = 0; j < scoreCount; j++) {
                Score score = new Score();
                score.setPositionId(positionIds.get(j));
                score.setProcessID(processId);
                score.setTotal(random.nextDouble() * 100); // 0-100的总分
                score.setPOp(process);
                score.setRemark(""); // 初始化remark为空字符串

                // 初始化分数项数组，包含随机分数
                double[] scoreItems = new double[20];
                for (int k = 0; k < scoreItems.length; k++) {
                    scoreItems[k] = random.nextDouble() * 50; // 0-50的分数项
                }
                score.setScoreItem(scoreItems);

                scores.add(score);
            }
        }

        // 特殊处理：模拟手动案例2的场景，创建一些能返回false的随机案例
        // 选择50%的案例进行特殊处理，提高生成false结果的概率
        if (random.nextInt(10) < 5 && !processIds.isEmpty() && !positionIds.isEmpty() && !fullOrderId2Order.isEmpty()) {
            // 随机选择一个订单
            List<String> orderNumList = new ArrayList<>(fullOrderId2Order.keySet());
            String specialOrderNum = orderNumList.get(random.nextInt(orderNumList.size()));
            OrderDto specialOrder = fullOrderId2Order.get(specialOrderNum);
            
            // 获取该订单的工序
            Map<Long, Map<Integer, OrderProcess>> orderProcesses = specialOrder.getMOrderProcessSetGroupByPart();
            if (orderProcesses != null && !orderProcesses.isEmpty()) {
                Map<Integer, OrderProcess> partProcesses = orderProcesses.get(100L);
                if (partProcesses != null && partProcesses.size() >= 2) {
                    // 获取工序列表并按序号排序
                    List<Map.Entry<Integer, OrderProcess>> processEntries = new ArrayList<>(partProcesses.entrySet());
                    processEntries.sort(Map.Entry.comparingByKey());
                    
                    if (processEntries.size() >= 2) {
                        // 选择两个不同的工序（第一个作为当前在产工序，第二个作为测试工序）
                        OrderProcess currentProcess = processEntries.get(0).getValue();
                        OrderProcess testProcess = processEntries.get(1).getValue();
                        
                        // 确保两个工序不同
                        if (currentProcess.getProcessId() != testProcess.getProcessId()) {
                            // 随机选择一个工位
                            Long specialPositionId = positionIds.get(random.nextInt(positionIds.size()));
                            PositionDto specialPosition = pPositionDtos.get(specialPositionId);
                            
                            // 设置工位为非空闲状态
                            if (specialPosition != null) {
                                specialPosition.setMiPosStatus(Global.BUSY_P_S); // 非空闲状态
                                specialPosition.setMBoxInPro("BOX" + String.format("%05d", specialPositionId));
                                specialPosition.setMBoxWaitingForPro("");
                                
                                // 更新工位状态
                                pPositionDtos.put(specialPositionId, specialPosition);
                            }
                            
                            // 设置当前工序的调度信息，使其正在该工位上执行
                            ProcessSch currentScheduling = currentProcess.getMScheduling();
                            if (currentScheduling != null) {
                                Set<Long> workingPos = new HashSet<>();
                                workingPos.add(specialPositionId);
                                currentScheduling.setMisWorkingPos(workingPos);
                                
                                // 设置做过的工位（测试工位没有做过）
                                Set<Long> haveDonePos = new HashSet<>();
                                haveDonePos.add(specialPositionId + 100000L); // 不存在的工位
                                currentScheduling.setMisHaveDonePos(haveDonePos);
                                
                                // 设置在库件数 (设置得足够小以便触发条件)
                                CBoxSet boxesInLib = new CBoxSet();
                                boxesInLib.setMiCutCnt(2); // 2裁片件数 (很小)
                                boxesInLib.setMiBoxCnt(1);   // 1个筐 (很小)
                                currentScheduling.setMBoxesInLib(boxesInLib);
                                
                                currentProcess.setMScheduling(currentScheduling);
                                
                                // 更新工序集
                                hProcessSet.put(currentProcess.getProcessId(), currentProcess);
                                
                                // 更新订单中的工序
                                partProcesses.put(currentProcess.getMiPartSeqNum(), currentProcess);
                                orderProcesses.put(100L, partProcesses);
                                specialOrder.setMOrderProcessSetGroupByPart(orderProcesses);
                                fullOrderId2Order.put(specialOrderNum, specialOrder);
                            }
                            
                            // 为测试工序设置调度信息
                            ProcessSch testScheduling = testProcess.getMScheduling();
                            if (testScheduling != null) {
                                // 设置在产工位 (无工位正在做)
                                Set<Long> testWorkingPos = new HashSet<>();
                                testScheduling.setMisWorkingPos(testWorkingPos);

                                // 设置做过的工位 (测试工位没有做过)
                                Set<Long> testHaveDonePos = new HashSet<>();
                                testHaveDonePos.add(specialPositionId + 100000L); // 不存在的工位
                                testScheduling.setMisHaveDonePos(testHaveDonePos);

                                // 设置在库件数 (设置得足够小以便触发条件)
                                CBoxSet testBoxesInLib = new CBoxSet();
                                testBoxesInLib.setMiCutCnt(2); // 2裁片件数 (很小)
                                testBoxesInLib.setMiBoxCnt(1);   // 1个筐 (很小)
                                testScheduling.setMBoxesInLib(testBoxesInLib);

                                testProcess.setMScheduling(testScheduling);
                                
                                // 更新工序集
                                hProcessSet.put(testProcess.getProcessId(), testProcess);
                            }
                            
                            // 创建特殊的分数数据，模仿手动案例2的条件
                            Score specialScore = new Score();
                            specialScore.setPositionId(specialPositionId);
                            specialScore.setProcessID(testProcess.getProcessId());
                            specialScore.setTotal(85.0);
                            specialScore.setPOp(testProcess);
                            specialScore.setRemark("");
                            
                            double[] specialScoreItems = new double[20];
                            Arrays.fill(specialScoreItems, 6.0);
                            specialScore.setScoreItem(specialScoreItems);
                            
                            scores.add(specialScore);
                        }
                    }
                }
            }
        }
        
        // 额外处理：创建更多能返回false的随机案例
        // 选择30%的案例进行额外特殊处理
        if (random.nextInt(10) < 3 && !processIds.isEmpty() && !positionIds.isEmpty() && !fullOrderId2Order.isEmpty()) {
            // 随机选择一个工序
            Long specialProcessId = processIds.get(random.nextInt(processIds.size()));
            OrderProcess specialProcess = hProcessSet.get(specialProcessId);
            
            if (specialProcess != null) {
                // 随机选择一个工位
                Long specialPositionId = positionIds.get(random.nextInt(positionIds.size()));
                PositionDto specialPosition = pPositionDtos.get(specialPositionId);
                
                // 设置工位为非空闲状态
                if (specialPosition != null) {
                    // 70%概率设置为忙碌状态，30%概率设置为其他非空闲状态
                    if (random.nextInt(10) < 7) {
                        specialPosition.setMiPosStatus(Global.BUSY_P_S);
                    } else {
                        int[] nonFreeStatus = {Global.IN_PRO_ONLY_P_S, Global.WAITING_FOR_ONLY_PRO_P_S, Global.IN_THE_WAY_P_S, Global.STOP_RECV_P_S};
                        specialPosition.setMiPosStatus(nonFreeStatus[random.nextInt(nonFreeStatus.length)]);
                    }
                    specialPosition.setMBoxInPro("BOX" + String.format("%05d", specialPositionId));
                    specialPosition.setMBoxWaitingForPro("");
                    
                    // 更新工位状态
                    pPositionDtos.put(specialPositionId, specialPosition);
                }
                
                // 为该工序设置调度信息
                ProcessSch scheduling = specialProcess.getMScheduling();
                if (scheduling != null) {
                    // 设置在产工位
                    Set<Long> workingPos = new HashSet<>();
                    workingPos.add(specialPositionId);
                    scheduling.setMisWorkingPos(workingPos);
                    
                    // 设置做过的工位
                    Set<Long> haveDonePos = new HashSet<>();
                    haveDonePos.add(specialPositionId + 100000L); // 不存在的工位
                    scheduling.setMisHaveDonePos(haveDonePos);
                    
                    // 设置在库件数 (设置得足够小以便触发条件)
                    CBoxSet boxesInLib = new CBoxSet();
                    boxesInLib.setMiCutCnt(random.nextInt(5) + 1); // 1-5裁片件数
                    boxesInLib.setMiBoxCnt(1);   // 1个筐
                    scheduling.setMBoxesInLib(boxesInLib);
                    
                    specialProcess.setMScheduling(scheduling);
                    
                    // 更新工序集
                    hProcessSet.put(specialProcessId, specialProcess);
                }
                
                // 创建特殊的分数数据，模仿手动案例2的条件
                Score specialScore = new Score();
                specialScore.setPositionId(specialPositionId);
                specialScore.setProcessID(specialProcessId);
                specialScore.setTotal(80.0 + random.nextDouble() * 20); // 80-100的总分
                specialScore.setPOp(specialProcess);
                specialScore.setRemark("");
                
                double[] specialScoreItems = new double[20];
                for (int i = 0; i < specialScoreItems.length; i++) {
                    specialScoreItems[i] = 5.0 + random.nextDouble() * 5; // 5-10的分数项
                }
                specialScore.setScoreItem(specialScoreItems);
                
                scores.add(specialScore);
            }
        }

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/scores.json"), scores);
        // 更新工序集文件
        objectMapper.writeValue(new File(basePath + "/hProcessSet.json"), hProcessSet);
        // 更新工位数据文件
        objectMapper.writeValue(new File(basePath + "/pPositionDtos.json"), pPositionDtos);
        // 更新订单数据文件
        objectMapper.writeValue(new File(basePath + "/orderId2Order.json"), fullOrderId2Order);
    }

    public static void main(String[] args) {
        try {
            // 确保主目录存在
            File mainDir = new File("../../test_data/recheckCanSend_WeiChi");
            if (!mainDir.exists()) {
                mainDir.mkdirs();
            }

            // 生成50组随机测试数据
            for (int i = 1; i <= 50; i++) {
                generateRandomTestData(i);
                System.out.println("随机测试数据集 " + i + " 已成功生成");
            }

            // 生成2个手动测试案例
            for (int i = 1; i <= 2; i++) {
                generateManualTestData(i);
                System.out.println("手动测试案例 " + i + " 已成功生成");
            }

            System.out.println("所有测试数据已成功生成并保存到../../test_data/recheckCanSend_WeiChi目录下");
        } catch (IOException e) {
            System.err.println("生成测试数据时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
}